using System;
using System.Linq;
using System.Text;
using System.Web;
using System.Web.Mvc;
using Se.Framework.Common.Config.Providers;

namespace Se.Framework.Web.Mvc.GenericCrud.Attributes
{
    internal class QueryStringConvertionFilterAttribute : FilterAttribute, IActionFilter
    {
        private const string EntityKey = "Entity";
        private const string SidxKey = "sidx";
        private const string SordKey = "sord";
        private const string SearchKey = "_Search";

        private System.Reflection.PropertyInfo prop;

        private GenericCrudController<GenericCrudViewModel> controller;

        private IGridBuilder builder;

        private ValueProviderResult entityValue;

        public void OnActionExecuting(ActionExecutingContext filterContext)
        {
            prop = filterContext.HttpContext.Request.QueryString.GetType().GetProperty("IsReadOnly", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
            // Set the property false (writable)
            prop.SetValue(filterContext.HttpContext.Request.QueryString, false, null);

            // Have your way with it.
            var entityValue = filterContext.Controller.ValueProvider.GetValue(EntityKey);
            if (entityValue != null)
            {
                var controller = ((GenericCrudController<GenericCrudViewModel>)filterContext.Controller);
                var builder = GridBuilderFactory.Factory.FromType(TypeProviderManager.Default.GetTypeByClassName(entityValue.AttemptedValue));

                ConvertParameters(controller, filterContext.HttpContext.Request, SidxKey, builder);
                ConvertParameters(controller, filterContext.HttpContext.Request, SordKey, builder);
                var searchValue = filterContext.Controller.ValueProvider.GetValue(SearchKey);
                if (searchValue != null)
                {
                    bool isSearching = false;
                    if (bool.TryParse(searchValue.AttemptedValue, out isSearching) && isSearching)
                    {
                        foreach (var columnToConvert in builder.TableProperties.Columns.Values.Where(c => c.Convertion != null && c.Convertion.NameConvertionNeeded))
                        {
                            if (filterContext.HttpContext.Request.QueryString.AllKeys.Any(k => k.Equals(columnToConvert.Convertion.NameFrom)))
                            {
                                filterContext.HttpContext.Request.QueryString.Add(columnToConvert.Convertion.NameTo, filterContext.HttpContext.Request.QueryString[columnToConvert.Convertion.NameFrom]);
                                filterContext.HttpContext.Request.QueryString.Remove(columnToConvert.Convertion.NameFrom);
                            }
                        }
                    }
                }
            }
        }

        public void OnActionExecuted(ActionExecutedContext filterContext)
        {
            if (entityValue != null)
            {
                ConvertParameters(controller, filterContext.HttpContext.Request, SidxKey, builder, true);
                ConvertParameters(controller, filterContext.HttpContext.Request, SordKey, builder, true);
            }
            // Set the property true (ReadOnly)
            prop.SetValue(filterContext.HttpContext.Request.QueryString, true, null);
        }

        private static void ConvertParameters(GenericCrudController<GenericCrudViewModel> controller, HttpRequestBase request, string paramId, IGridBuilder builder, bool reverse = false)
        {
            var oldValue = controller.ValueProvider.GetValue(paramId);
            if (oldValue != null)
            {
                StringBuilder result = new StringBuilder();
                var aux = oldValue.AttemptedValue.Split(",".ToArray(), StringSplitOptions.RemoveEmptyEntries);
                foreach (var item in aux.Where(p => !string.IsNullOrWhiteSpace(p)))
                {
                    var aux2 = item.Split(" ".ToArray(), StringSplitOptions.RemoveEmptyEntries);
                    if (aux2.Length > 1)
                    {
                        var item2 = aux2[0];
                        if (!reverse)
                        {
                            var colunm = builder.TableProperties.Columns.Values.FirstOrDefault(c => c.Convertion != null && c.Convertion.NameFrom == item2);
                            result.AppendFormat("{0} {1},", colunm != null ? colunm.Convertion.NameTo : item2, aux2[1]);
                        }
                        else
                        {
                            var colunm = builder.TableProperties.Columns.Values.FirstOrDefault(c => c.Convertion != null && c.Convertion.NameTo == item2);
                            result.AppendFormat("{0} {1},", colunm != null ? colunm.Convertion.NameFrom : item2, aux2[1]);
                        }
                    }
                    else
                    {
                        result.Append(item);
                    }
                }
                request.QueryString.Set(paramId, result.ToString());
            }
        }
    }
}